package util

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"regexp"
	"strings"
	"time"
)

// 查找字符串中第一个IPV4地址
func MatchIPv4(s string) (string, error) {
	reg, err := regexp.Compile(`(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}`)
	if err != nil {
		return "", err
	}
	ip := reg.FindString(strings.TrimSpace(s))
	if ip == "" {
		return "", fmt.Errorf("not match ipv4 address")
	}
	return ip, nil
}

// 查找字符串中第一个IPV6地址
func MatchIPv6(s string) (string, error) {
	reg, err := regexp.Compile(`(?:(?:[a-fA-F\d]{1,4}:){7}(?:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,2}|:)|(?:[a-fA-F\d]{1,4}:){4}(?:(?::[a-fA-F\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,3}|:)|(?:[a-fA-F\d]{1,4}:){3}(?:(?::[a-fA-F\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,4}|:)|(?:[a-fA-F\d]{1,4}:){2}(?:(?::[a-fA-F\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,5}|:)|(?:[a-fA-F\d]{1,4}:){1}(?:(?::[a-fA-F\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?`)
	if err != nil {
		return "", err
	}
	ip := reg.FindString(strings.TrimSpace(s))
	if ip == "" {
		return "", fmt.Errorf("not match ipv6 address")
	}
	return ip, nil
}

// 获取ipv4地址接口
var ipv4Apis = []string{"http://ipv4.ddnspod.com", "http://ipv4.testipv6.cn/ip/", "http://ipv4.icanhazip.com/", "https://api4.ipify.org/", "https://ip4.seeip.org/", "http://api-ipv4.ip.sb/ip", "http://v4.ipv6-test.com/api/myip.php"}

// 获取ipv6地址接口
var ipv6Apis = []string{"http://ipv6.ddnspod.com", "http://ipv6.testipv6.cn/ip/", "http://ipv6.icanhazip.com/", "https://api6.ipify.org/", "https://ip6.seeip.org/", "http://api-ipv6.ip.sb/ip", "http://v6.ipv6-test.com/api/myip.php"}

func request(url string) (string, error) {
	client := &http.Client{Transport: CustomDnsWithNoProxyHttpTransport, Timeout: 3 * time.Second}
	req, err := http.NewRequest("GET", url, nil)

	if err != nil {
		return "", err
	}
	res, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer res.Body.Close()
	if !(res.StatusCode >= 200 && res.StatusCode < 300) {
		return "", fmt.Errorf("error status code: %d", res.StatusCode)
	}
	body, err := io.ReadAll(res.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}

// 获取当前上网的公网ip地址
//
// @param ipType: V4 或 V6
func GetPublicIP(ipType string) (string, error) {
	var apis []string
	var matchFn func(s string) (string, error)

	if ipType == "V6" {
		apis = ipv6Apis
		matchFn = MatchIPv6
	} else if ipType == "V4" {
		apis = ipv4Apis
		matchFn = MatchIPv4
	} else {
		return "", fmt.Errorf("error ipType: %s", ipType)
	}
	res := make(chan string, len(apis))
	for _, v := range apis {
		go func(url string) {
			body, err := request(url)
			if err != nil {
				log.Println(err)
				res <- ""
				return
			}
			ip, err := matchFn(body)
			if err != nil {
				log.Println(err)
				res <- ""
				return
			}
			res <- ip
		}(v)
	}

	ips := map[string]int{}
	successCount := 0
	for range apis {
		v := <-res
		if v == "" {
			continue
		}
		c := ips[v]
		ips[v] = c + 1
		successCount += 1
	}

	for k, v := range ips {
		if v >= successCount/2 {
			return k, nil
		}
	}
	return "", fmt.Errorf("not found ip%s address", ipType)
}
